package com.well.register.netty;

import com.well.register.config.PropertiesConfig;
import com.well.register.netty.handle.ServerEventHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * well rpc 主要服务进程。
 */
public class RpcServer {

    private static Logger logger = LoggerFactory.getLogger(RpcServer.class);
    private static EventLoopGroup boss = new NioEventLoopGroup();
    private static EventLoopGroup works = new NioEventLoopGroup();
    private static int READ_WAIT_SECONDS = 5;
    private static ServerBootstrap serverBootstrap = new ServerBootstrap();
    private static  ChannelFuture f = null;
    private static  SslContext sslCtx = null;

    public static synchronized void run( Integer port) {
        serverBootstrap.group(boss, works)
                .channel(NioServerSocketChannel.class)
                .childHandler(new HeartBeatServerInitializer(sslCtx));
        try {
            // 服务器绑定端口监听
            f = serverBootstrap.bind(port).sync();
            logger.info("server start ,port: " + port);
            // 监听服务器关闭监听，此方法会阻塞
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            works.shutdownGracefully();
        }
    }

    public static void run(PropertiesConfig propertiesConfig) {
        if (propertiesConfig.getEnableSSL()) {
            ServerSsl serverSsl = new ServerSsl(propertiesConfig);
            sslCtx = serverSsl.getSslContext();
        }
        run(propertiesConfig.getPort());
    }

    private static class HeartBeatServerInitializer extends ChannelInitializer<SocketChannel> {

        private SslContext sslContext;
        public HeartBeatServerInitializer(SslContext sslContext) {
            this.sslContext = sslContext;
        }

        @Override
        protected void initChannel(SocketChannel ch) {
            ChannelPipeline pipeline = ch.pipeline();
            if (sslContext != null) {
                pipeline.addLast(sslContext.newHandler(ch.alloc()));
            }
            // 监听读操作,读超时时间为5秒，超过5秒关闭channel;
            pipeline.addLast(new IdleStateHandler(READ_WAIT_SECONDS, 0, 0, TimeUnit.SECONDS));
            pipeline.addLast(new ObjectEncoder());
            pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE,
                    ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
            pipeline.addLast(new ServerEventHandler(sslContext));
        }
    }

    public static void main(String[] args) {
        run(9999);
    }

}
